﻿using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;

namespace MuXue.Zyiz.Template.Common.Redis
{
    /// <summary>
    /// Redis 辅助类
    /// </summary>
    public class RedisHelper
    {
        private static ConnectionMultiplexer RedisConnectionManager;
        private static object locks = new object();
        public static IConfigurationSection _config;
        public static IDatabase Redis
        {
            get
            {
                try
                {
                    if (RedisConnectionManager != null && !RedisConnectionManager.IsConnected)
                    {
                        RedisConnectionManager.Dispose();
                        RedisConnectionManager = null;
                    }
                    if (RedisConnectionManager == null)
                    {
                        lock (locks)
                        {
                            if (RedisConnectionManager == null)
                            {
                                if (_config["isSentinel"] == "true")
                                {
                                    RedisConnectionManager = RedisConn.RedisConnBySentinel(_config);
                                }
                                else
                                {
                                    RedisConnectionManager = ConnectionMultiplexer.Connect(_config["Connection"]);
                                }
                            }
                        }
                    }
                    return RedisConnectionManager.GetDatabase(Convert.ToInt32(_config["db"]));
                }
                catch (Exception e)
                {
                    RedisConnectionManager.Dispose();
                    RedisConnectionManager = null;
                    LogHelper.Error("Redis Error:" + e.Message, e);
                    return null;
                }

            }
        }
        public static void Set(string key, string value, int expiretime = 0)
        {
            try
            {
                if (expiretime != 0)
                {
                    TimeSpan span = DateTime.Now.AddSeconds(expiretime) - DateTime.Now;
                    Redis.StringSet(key, value, span);
                }
                else
                {
                    Redis.StringSet(key, value);
                }
            }
            catch (Exception e)
            {
                RedisConnectionManager.Dispose();
                RedisConnectionManager = null;
                LogHelper.Error("Redis Error:" + e.Message, e);
            }
        }
        public static void Set<T>(string key, T value, int expiretime = 0)
        {
            try
            {

                if (expiretime != 0)
                {
                    TimeSpan span = DateTime.Now.AddSeconds(expiretime) - DateTime.Now;
                    Redis.StringSet(key, JsonConvert.SerializeObject(value), span);
                }
                else
                {
                    Redis.StringSet(key, JsonConvert.SerializeObject(value));
                }
            }
            catch (Exception e)
            {
                RedisConnectionManager.Dispose();
                RedisConnectionManager = null;
                LogHelper.Error("Redis Error:" + e.Message, e);
            }
        }
        public static void SetHash(string key, HashEntry[] value, int expiretime = 0)
        {
            try
            {

                Redis.HashSet(key, value);
                if (expiretime != 0)
                {
                    TimeSpan span = DateTime.Now.AddSeconds(expiretime) - DateTime.Now;
                    Redis.KeyExpire(key, span);
                }
            }
            catch (Exception e)
            {
                RedisConnectionManager.Dispose();
                RedisConnectionManager = null;
                LogHelper.Error("Redis Error:" + e.Message, e);
            }
        }
        /// <summary>
        /// 整个List重新SET
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="list"></param>
        /// <param name="expiretime"></param>
        public static void SetList<T>(string key, IList<T> list, int expiretime = 0)
        {
            try
            {
                if (list != null && list.Count > 0)
                {
                    RedisValue[] lists = new RedisValue[list.Count];
                    if (list != null && list.Count > 0)
                    {
                        for (int i = 0; i < list.Count; i++)
                        {
                            lists[i] = JsonConvert.SerializeObject(list[i]);
                        }
                        Redis.KeyDelete(key);
                        Redis.ListRightPush(key, lists);
                        if (expiretime != 0)
                        {
                            TimeSpan span = DateTime.Now.AddSeconds(expiretime) - DateTime.Now;
                            Redis.KeyExpire(key, span);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                RedisConnectionManager.Dispose();
                RedisConnectionManager = null;
                LogHelper.Error("Redis Error:" + e.Message, e);
            }
        }
        /// <summary>
        /// LIST中的某个Item重新SET
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="index"></param>
        /// <param name="value"></param>
        public static void SetListItem<T>(string key, int index, T value)
        {
            try
            {

                Redis.ListSetByIndex(key, index, JsonConvert.SerializeObject(value));
            }
            catch (Exception e)
            {
                RedisConnectionManager.Dispose();
                RedisConnectionManager = null;
                LogHelper.Error("Redis Error:" + e.Message, e);
            }
        }
        public static void AppendListItem<T>(string key, T value)
        {
            try
            {

                Redis.ListRightPush(key, JsonConvert.SerializeObject(value));
            }
            catch (Exception e)
            {
                RedisConnectionManager.Dispose();
                RedisConnectionManager = null;
                LogHelper.Error("Redis Error:" + e.Message, e);
            }
        }
        public static void AppendList<T>(string key, IList<T> list)
        {
            try
            {

                RedisValue[] lists = new RedisValue[list.Count];
                if (list != null && list.Count > 0)
                {
                    for (int i = 0; i < list.Count; i++)
                    {
                        lists[i] = JsonConvert.SerializeObject(list[i]);
                    }
                    Redis.ListRightPush(key, lists);
                }
            }
            catch (Exception e)
            {
                RedisConnectionManager.Dispose();
                RedisConnectionManager = null;
                LogHelper.Error("Redis Error:" + e.Message, e);
            }
        }


        public static string Get(string key)
        {
            try
            {

                return Redis.StringGet(key);
            }
            catch (Exception e)
            {
                RedisConnectionManager.Dispose();
                RedisConnectionManager = null;
                LogHelper.Error("Redis Error:" + e.Message, e);
                return "";
            }
        }
        public static T Get<T>(string key) where T : class
        {
            try
            {

                string sg = Redis.StringGet(key);
                if (!string.IsNullOrEmpty(sg))
                {
                    return JsonConvert.DeserializeObject<T>(sg);
                }
                return null;
            }
            catch (Exception e)
            {
                RedisConnectionManager.Dispose();
                RedisConnectionManager = null;
                LogHelper.Error("Redis Error:" + e.Message, e);
                return null;
            }
        }
        public static HashEntry[] GetHash(string key)
        {
            try
            {

                return Redis.HashGetAll(key);
            }
            catch (Exception e)
            {
                RedisConnectionManager.Dispose();
                RedisConnectionManager = null;
                LogHelper.Error("Redis Error:" + e.Message, e);
                return null;
            }
        }
        public static List<T> GetList<T>(string key, int start, int end) where T : class
        {
            try
            {

                long count = Redis.ListLength(key);
                if (count < end)
                {
                    end = (int)count;
                }
                RedisValue[] arr = Redis.ListRange(key, start, end);

                List<T> list = null;
                if (arr != null && arr.Length > 0)
                {
                    list = new List<T>();
                    foreach (string item in arr)
                    {
                        list.Add(JsonConvert.DeserializeObject<T>(item));
                    }
                }
                return list;
            }
            catch (Exception e)
            {
                RedisConnectionManager.Dispose();
                RedisConnectionManager = null;
                LogHelper.Error("Redis Error:" + e.Message, e);
                return null;
            }
        }
        public static List<T> GetList<T>(string key) where T : class
        {
            try
            {

                List<T> list = new List<T>();
                long count = Redis.ListLength(key);
                for (int i = 0; i < count; i += 1000)
                {
                    List<T> strList = GetList<T>(key, i, i + 999);
                    if (strList != null && strList.Count > 0)
                    {
                        list.AddRange(strList);
                    }
                }
                if (list != null && list.Count > 0)
                {
                    return list;
                }
                else
                {
                    return null;
                }
            }
            catch (Exception e)
            {
                RedisConnectionManager.Dispose();
                RedisConnectionManager = null;
                LogHelper.Error("Redis Error:" + e.Message, e);
                return null;
            }
        }
        public static T GetListItem<T>(string key, int index) where T : class
        {
            try
            {

                long count = Redis.ListLength(key);
                if (count <= index)
                {
                    return null;
                }
                RedisValue item = Redis.ListGetByIndex(key, index);
                return JsonConvert.DeserializeObject<T>(item);
            }
            catch (Exception e)
            {
                RedisConnectionManager.Dispose();
                RedisConnectionManager = null;
                LogHelper.Error("Redis Error:" + e.Message, e);
                return null;
            }
        }
        public static void Remove(string key)
        {
            try
            {
                Redis.KeyDelete(key);
            }
            catch (Exception e)
            {
                RedisConnectionManager.Dispose();
                RedisConnectionManager = null;
                LogHelper.Error("Redis Error:" + e.Message, e);
            }
        }
        public static void RemoveKeys(List<string> keys)
        {
            try
            {

                if (keys != null && keys.Count > 0)
                {
                    foreach (string item in keys)
                    {
                        Redis.KeyDelete(item);
                    }
                }
            }
            catch (Exception e)
            {
                RedisConnectionManager.Dispose();
                RedisConnectionManager = null;
                LogHelper.Error("Redis Error:" + e.Message, e);
            }
        }
        public static void ListRemove<T>(string key, T value) where T : class
        {
            try
            {
                Redis.ListRemove(key, JsonConvert.SerializeObject(value));
            }
            catch (Exception e)
            {
                RedisConnectionManager.Dispose();
                RedisConnectionManager = null;
                LogHelper.Error("Redis Error:" + e.Message, e);
            }
        }
        public static List<T> ListLeftPop<T>(string key, int count = 1) where T : class
        {
            try
            {

                long len = Redis.ListLength(key);
                if (count > len)
                {
                    count = Convert.ToInt32(len);
                }
                if (count > 0)
                {
                    List<T> list = new List<T>();
                    for (int i = 0; i < count; i++)
                    {
                        String value = Redis.ListLeftPop(key);
                        if (String.IsNullOrEmpty(value))
                        {
                            break;
                        }
                        list.Add(JsonConvert.DeserializeObject<T>(value));
                    }
                    return list;
                }
                else
                {
                    return null;
                }
            }
            catch (Exception e)
            {
                RedisConnectionManager.Dispose();
                RedisConnectionManager = null;
                LogHelper.Error("Redis Error:" + e.Message, e);
                return null;
            }
        }
        public static List<T> ListRightPop<T>(string key, int count = 1) where T : class
        {
            try
            {

                long len = Redis.ListLength(key);
                if (count > len)
                {
                    count = Convert.ToInt32(len);
                }
                if (count > 0)
                {
                    List<T> list = new List<T>();
                    for (int i = 0; i < count; i++)
                    {
                        String value = Redis.ListRightPop(key);
                        if (String.IsNullOrEmpty(value))
                        {
                            break;
                        }
                        list.Add(JsonConvert.DeserializeObject<T>(Redis.ListRightPop(value)));
                    }
                    return list;
                }
                else
                {
                    return null;
                }
            }
            catch (Exception e)
            {
                RedisConnectionManager.Dispose();
                RedisConnectionManager = null;
                LogHelper.Error("Redis Error:" + e.Message, e);
                return null;
            }
        }
        public static void KeyExpire(string key, int expiretime)
        {
            try
            {
                TimeSpan span = DateTime.Now.AddSeconds(expiretime) - DateTime.Now;
                Redis.KeyExpire(key, span);
            }
            catch (Exception e)
            {
                RedisConnectionManager.Dispose();
                RedisConnectionManager = null;
                LogHelper.Error("Redis Error:" + e.Message, e);
            }
        }
    }
}